package com.startup.yellocar.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.Namespace;



public class TestGenerator {

	Document doc;
	Namespace ns;
	String dtoBaseName = "com.startup.yellocar.dto";
	String packagename = "com.startup.yellocar"; 
	
	public TestGenerator(Document doc, Namespace ns, String dtoBaseName) {
		super();
		this.doc = doc;
		this.ns = ns;
		this.dtoBaseName = dtoBaseName;
	}
	
	public String initGenerate(Element complexTypeElement){
		
		 String complexTypeName = complexTypeElement.getAttributeValue("name");
		 System.out.println("TextGenerator#initGenerate complexTypeName : "+complexTypeName);
		 String dTOClassName=UtilGenerator.firstToUpper(complexTypeName);
		 String dAOClassName=dTOClassName.replaceAll("DTO","DAO");
		 String dTOVarName=UtilGenerator.firstToLower(dTOClassName);
		 String dAOVarName=UtilGenerator.firstToLower(dAOClassName);
		 
		 StringBuilder strBuilder = new StringBuilder();
			strBuilder.append("package "+packagename+".dao;\n\n");
			strBuilder.append("import org.junit.Assert;\n");
			strBuilder.append("import org.junit.FixMethodOrder;\n");
			strBuilder.append("import org.junit.Test;\n");
			strBuilder.append("import java.util.Date;\n");
			strBuilder.append("import java.util.List;\n\n");
			
			strBuilder.append("import org.junit.runner.RunWith;\n");
			strBuilder.append("import org.junit.runners.MethodSorters;\n");
			strBuilder.append("import org.springframework.beans.factory.annotation.Autowired;\n");
			strBuilder.append("import org.springframework.test.context.ContextConfiguration;\n");
			strBuilder.append("import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;\n");
			strBuilder.append("import "+packagename+".dto.*;\n");
			strBuilder.append("import "+packagename+".dao."+dAOClassName+";\n\n");
			
			strBuilder.append("@RunWith(SpringJUnit4ClassRunner.class)\n");
			strBuilder.append("@ContextConfiguration(locations = { \"classpath:spring-servlet.xml\" })\n");
			strBuilder.append("@FixMethodOrder(MethodSorters.NAME_ASCENDING)\n");
			
			strBuilder.append("public class Test"+dAOClassName+" {\n\n"); 
			strBuilder.append("	@Autowired\n");
			strBuilder.append("	private "+dAOClassName+" "+dAOVarName+";\n");
			strBuilder.append("	private static "+dTOClassName+" "+dTOVarName+";\n\n");
			
			return strBuilder.toString();
	}
	
	
	public String testInsertGenerate(Element complexTypeElement) {
		String complexTypeName = complexTypeElement.getAttributeValue("name");
		if (UtilGenerator.containt(complexTypeName, "DTO")) {
			System.out.println("TestGenarator#testInsertGenerate complexTypeName : "+ complexTypeName);
			String dTOClassName = UtilGenerator.firstToUpper(complexTypeName);
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			String dAOClassName = dTOClassName.replaceAll("DTO", "DAO");
			String dAOVarName = UtilGenerator.firstToLower(dAOClassName);
			StringBuilder strBuilder = new StringBuilder();
			strBuilder.append("	@Test\n");
			strBuilder.append("	public void test1Insert() {\n\n");
			strBuilder.append("		" +dTOVarName + " ="+ newInstance(dtoBaseName,dTOClassName)+";\n" );
			strBuilder.append("		" + dAOVarName + ".insert(" + dTOVarName + ");\n");
			strBuilder.append("		Assert.assertNotNull(" + dTOVarName + ".getId());\n");
			strBuilder.append("	}\n\n");
			return strBuilder.toString();
		}
		return "";
	}
	
	public String testGetGenerate(Element complexTypeElement) {
		String complexTypeName = complexTypeElement.getAttributeValue("name");
		if (UtilGenerator.containt(complexTypeName, "DTO")) {
			System.out.println("TestGenarator#testGetGenerate complexTypeName : "+ complexTypeName);
			String dTOClassName = UtilGenerator.firstToUpper(complexTypeName);
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			String dAOClassName = dTOClassName.replaceAll("DTO", "DAO");
			String dAOVarName = UtilGenerator.firstToLower(dAOClassName);
			StringBuilder strBuilder = new StringBuilder();
			strBuilder.append("	@Test\n");
			strBuilder.append("	public void test3Get() {\n\n");
			strBuilder.append("		int id = "+dTOVarName+".getId();\n" );
			strBuilder.append("		" +dTOVarName  + " = "+dAOVarName+".get(id);\n");
			strBuilder.append("		Assert.assertEquals("+dTOVarName+".getId().intValue(), id);\n");
			strBuilder.append("	}\n\n");
			return strBuilder.toString();
		}
		return "";
	}
	
	public String testGetAllGenerate(Element complexTypeElement) {
		String complexTypeName = complexTypeElement.getAttributeValue("name");
		if (UtilGenerator.containt(complexTypeName, "DTO")) {
			System.out.println("TestGenarator#testGetAllGenerate complexTypeName : "+ complexTypeName);
			String dTOClassName = UtilGenerator.firstToUpper(complexTypeName);
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			String dAOClassName = dTOClassName.replaceAll("DTO", "DAO");
			String dAOVarName = UtilGenerator.firstToLower(dAOClassName);
			StringBuilder strBuilder = new StringBuilder();
			strBuilder.append("	@Test\n");
		    strBuilder.append("	public void test4GetAll() {\n\n");
			strBuilder.append("		List<"+dTOClassName+"> listOf"+dTOVarName+" = "+dAOVarName+".getAll();\n" );
			strBuilder.append("		Assert.assertNotNull(listOf"+dTOVarName+");\n");
			strBuilder.append("		Assert.assertEquals(true,listOf"+dTOVarName+".size()>0);\n");
			strBuilder.append("	}\n\n");
			return strBuilder.toString();
		}
		return "";
	}
	
	public String testDeleteGenerate(Element complexTypeElement) {
		String complexTypeName = complexTypeElement.getAttributeValue("name");
		if (UtilGenerator.containt(complexTypeName, "DTO")) {
			System.out.println("TestGenarator#testDeleteGenerate complexTypeName : "+ complexTypeName);
			String dTOClassName = UtilGenerator.firstToUpper(complexTypeName);
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			String dAOClassName = dTOClassName.replaceAll("DTO", "DAO");
			String dAOVarName = UtilGenerator.firstToLower(dAOClassName);
			StringBuilder strBuilder = new StringBuilder();
			strBuilder.append("	@Test\n");
			strBuilder.append("	public void test5Delete() {\n\n");
			strBuilder.append("		int id = "+dTOVarName+".getId();\n" );
			strBuilder.append("		" +dAOVarName+".delete("+dTOVarName+");\n");
			strBuilder.append("		" +dTOVarName  +  " = "+dAOVarName+".get(id);\n");
			strBuilder.append("		Assert.assertNull("+dTOVarName+");\n");
			strBuilder.append("	}\n\n");
			return strBuilder.toString();
		}
		return "";
	}
	
	public String testUpdateGenerate(Element complexTypeElement) {
		String complexTypeName = complexTypeElement.getAttributeValue("name");
		if (UtilGenerator.containt(complexTypeName, "DTO")) {
			
			System.out.println("TestGenarator#testUpdateGenerate complexTypeName : "+ complexTypeName);
			String dTOClassName = UtilGenerator.firstToUpper(complexTypeName);
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			String dAOClassName = dTOClassName.replaceAll("DTO", "DAO");
			String dAOVarName = UtilGenerator.firstToLower(dAOClassName);
			Map<String, String> setter = getSetter( dtoBaseName,  dTOClassName);
			
			if(setter!=null){
				StringBuilder strBuilder = new StringBuilder();
				strBuilder.append("	@Test\n");
				strBuilder.append("	public void test2Update() {\n\n");
				if(!setter.isEmpty())
				{
					strBuilder.append("		int id = "+dTOVarName+".getId();\n" );
					
					strBuilder.append("		" + dTOVarName+"."+setter.get("name")+"("+setter.get("param")+");\n");
					strBuilder.append("		" +dAOVarName+".update("+dTOVarName+");\n");
					strBuilder.append("		" +dTOVarName  + " = "+dAOVarName+".get(id);\n");				
					String getter = setter.get("name").replaceFirst("set", "get");
					strBuilder.append("		Assert.assertEquals("+dTOVarName+"."+getter+"(),"+setter.get("param")+");\n");
				
				}
					
				strBuilder.append("	}\n\n");
				return strBuilder.toString();
			}
		}
		return "";
	}
	
	public String endGenerate() {    
		StringBuilder strBuilder = new StringBuilder();
		strBuilder.append("}\n");
		return strBuilder.toString();
	}
	public void generate() {
		Element rootNode = doc.getRootElement();
		List<Element> list = rootNode.getChildren("complexType",ns);
		for(Element element:list)
		{
			  String name = element.getAttributeValue("name");
			  if(UtilGenerator.containt(name, "DTO"))
			  {
			   daoConstuct(element);
			  }
		}
		
	}
	public void daoConstuct(Element complexTypeElement) {  
		  String complexTypeName = complexTypeElement.getAttributeValue("name");
	        
	        System.out.println("testGenerator#daoConstuct complexTypeName : "+complexTypeName);	       
	        String dTOClassName=UtilGenerator.firstToUpper(complexTypeName);
	        
		StringBuilder strBuilder = new StringBuilder();
		strBuilder.append(initGenerate(complexTypeElement));
		strBuilder.append(testInsertGenerate(complexTypeElement));
		strBuilder.append(testUpdateGenerate(complexTypeElement));
		strBuilder.append(testGetGenerate(complexTypeElement));
		strBuilder.append(testGetAllGenerate(complexTypeElement));
		strBuilder.append(testDeleteGenerate(complexTypeElement));
		strBuilder.append(endGenerate());
		
		File file = new File(UtilGenerator.testDAOPath(dTOClassName));
		FileWriter fw;
		BufferedWriter bw;
		try {
			fw = new FileWriter(file.getAbsoluteFile());
			 bw= new BufferedWriter(fw);
			bw.write(strBuilder.toString());
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	public String newInstance(String dtoBaseName, String dTOClassName){
		

		try {
			Class<?> clazz = Class.forName(dtoBaseName+"."+dTOClassName);
			Constructor<?>[] constructeurs = clazz.getConstructors();
			Constructor<?> c = constructeurs[0];
			for (Constructor<?> constructor : constructeurs) {
				
				if(constructor.getParameterTypes().length!=0){
					c = constructor;
					
				}
			}
			String dTOVarName = UtilGenerator.firstToLower(dTOClassName);
			
			String newDTO =  " new " + dTOClassName + "( ";
			Class<?>[] parameterType = c.getParameterTypes();
			for (Class<?> class1 : parameterType) {
				if(class1.toString().endsWith("DTO")){
					continue;
				}
				else if(class1.toString().toLowerCase().contains("date"))
					newDTO+="new Date(),";
				else if(class1.toString().toLowerCase().contains("string"))
					newDTO += "\"Test Case\",";
				else if(class1.toString().toLowerCase().contains("boolean"))
					newDTO += true+",";
				else if(class1.toString().toLowerCase().contains("double"))
					newDTO += 15.75+",";
				else if(class1.toString().toLowerCase().contains("long"))
					newDTO += "new Long(18),";
				else if(class1.toString().contains("Enum"))
					newDTO += class1.getCanonicalName()+".getDefault(),";
				else
					newDTO+=14+",";
				
			}
			if(newDTO.endsWith(",")){
				char[] t = newDTO.toCharArray();
				t[t.length-1]=' ';
				newDTO = String.copyValueOf( t);
			}
			newDTO += ")";

			return newDTO;
			
		} catch (ClassNotFoundException e) {
			
			System.out.println(e.getMessage());
		}
		return "";
	}
	
	public Map<String , String> getSetter(String dtoBaseName, String dTOClassName){
		
		try {
			Class<?> clazz = Class.forName(dtoBaseName+"."+dTOClassName);
			Method[] methods = clazz.getMethods();
			String setterParam ="";
			for (Method method : methods) {
				if((method.getName().startsWith("set"))&&(!method.getName().contains("Id"))&&(!method.getName().contains("DTO")))
				{	
					
					Class<?> clazz1 = method.getParameterTypes()[0];
					if(clazz1.toString().toLowerCase().contains("date"))
						continue;
					else if(clazz1.toString().toLowerCase().contains("string"))
						setterParam = "\""+method.getName()+"\"";
					else if(clazz1.toString().toLowerCase().contains("boolean"))
						setterParam = "true";
					else if(clazz1.toString().toLowerCase().contains("double"))
						setterParam += 15.75;
					else if(clazz1.toString().toLowerCase().contains("long"))
						setterParam += "new Long(18)";
					else
						setterParam=null;
					Map<String, String> result = new HashMap<String, String>();
					if(setterParam!=null)
					{
						result.put("name",  method.getName());
						result.put("param",  setterParam);
					}
				
					return result;
				}
			}
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
		
		return null;
	}
	
}
